{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 1. Object Oriented Programming" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this exploration, we examine the idea of an object, and begin writing our first object-oriented programming study." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#Table of Contents\n", "* [1. Object Oriented Programming](#1.-Object-Oriented-Programming)\n", "\t* [1.1 Old Ball Code](#1.1-Old-Ball-Code)\n", "\t* [1.2 Bouncing Ball as an Object](#1.2-Bouncing-Ball-as-an-Object)\n", "\t* [1.3 Introducing Arrays](#1.3-Introducing-Arrays)\n", "\t* [1.4 Variations](#1.4-Variations)\n", "\t* [1.5 Collision Detection](#1.5-Collision-Detection)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.1 Old Ball Code" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This code is from the discussion on Bouncing Balls. We need to keep track of the ball's velocities in the `x` and `y` direction, keep track of where it is (`x`, `y`), and the global time. " ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " var component = document.getElementById(\"sketch_6\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"state_6\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"controls_div_6\");\n", " if (component != undefined)\n", " component.remove();\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " // FIXME: Stop all previously running versions (?)\n", " var processingInstance = Processing.getInstanceById(\"canvas_6\");\n", " if (processingInstance != undefined && processingInstance.isRunning())\n", " processingInstance.noLoop();\n", " });\n", "\n", "\n", " var output_area = this;\n", " // find my cell element\n", " var cell_element = output_area.element.parents('.cell');\n", " // which cell is it?\n", " var cell_idx = Jupyter.notebook.get_cell_elements().index(cell_element);\n", " // get the cell object\n", " var cell = Jupyter.notebook.get_cell(cell_idx);\n", "\n", " function jyp_print(cell, newline) {\n", " return function(message) {\n", " cell.get_callbacks().iopub.output({header: {\"msg_type\": \"stream\"},\n", " content: {text: message + newline,\n", " name: \"stdout\"}});\n", " }\n", " }\n", " window.jyp_println = jyp_print(cell, \"\\n\");\n", " window.jyp_print = jyp_print(cell, \"\");\n", "\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " Processing.logger.println = jyp_print(cell, \"\\n\");\n", " Processing.logger.print = jyp_print(cell, \"\");\n", " });\n", "\n", "\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " Sketch #6:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #6 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "float g = 9.8; \n", "float dt; \n", "float t;\n", "\n", "float vx1;\n", "float vy1;\n", "float x1;\n", "float y1;\n", "\n", "float vx2;\n", "float vy2;\n", "float x2;\n", "float y2;\n", "\n", "void setup() {\n", " size(200, 500);\n", " dt = 0.1; \n", " t = 0;\n", " x1 = width/2;\n", " y1 = 50;\n", " vx1 = 50.0;\n", " vy1 = 0.0;\n", " x2 = width/2;\n", " y2 = 25;\n", " vx2 = -50.0;\n", " vy2 = -10.0;\n", "}\n", "\n", "void drawBall(float x, float y, int w, int h) {\n", " fill(255, 0, 0);\n", " ellipse(x, y, w, h);\n", "}\n", "\n", "void draw() {\n", " background(200);\n", " // gravity\n", " vy1 = vy1 + g * dt;\n", " \n", " float dx = vx1 * dt; \n", " if (((x1 + dx) > width) || ((x1 + dx) < 0)) {\n", " vx1 = vx1 * -0.8;\n", " } else {\n", " x1 = x1 + dx;\n", " }\n", "\n", " vy2 = vy2 + g * dt;\n", " \n", " dx = vx2 * dt; \n", " if (((x2 + dx) > width) || ((x2 + dx) < 0)) {\n", " vx2 = vx2 * -0.8;\n", " } else {\n", " x2 = x2 + dx;\n", " }\n", "\n", " \n", " float dy = vy1 * dt;\n", " if (((y1 + dy) > height) || ((y1 + dy) < 0)) {\n", " vy1 = vy1 * -0.8;\n", " } else {\n", " y1 = y1 + dy;\n", " }\n", "\n", " dy = vy2 * dt;\n", " if (((y2 + dy) > height) || ((y2 + dy) < 0)) {\n", " vy2 = vy2 * -0.8;\n", " } else {\n", " y2 = y2 + dy;\n", " }\n", "\n", " drawBall(x1, y1, 10, 10);\n", " drawBall(x2, y2, 15, 15);\n", " \n", " t = t + dt;\n", "}" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "data": { "application/javascript": [ "\n", " var component = document.getElementById(\"sketch_9\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"state_9\");\n", " if (component != undefined)\n", " component.remove();\n", " component = document.getElementById(\"controls_div_9\");\n", " if (component != undefined)\n", " component.remove();\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " // FIXME: Stop all previously running versions (?)\n", " var processingInstance = Processing.getInstanceById(\"canvas_9\");\n", " if (processingInstance != undefined && processingInstance.isRunning())\n", " processingInstance.noLoop();\n", " });\n", "\n", "\n", " var output_area = this;\n", " // find my cell element\n", " var cell_element = output_area.element.parents('.cell');\n", " // which cell is it?\n", " var cell_idx = Jupyter.notebook.get_cell_elements().index(cell_element);\n", " // get the cell object\n", " var cell = Jupyter.notebook.get_cell(cell_idx);\n", "\n", " function jyp_print(cell, newline) {\n", " return function(message) {\n", " cell.get_callbacks().iopub.output({header: {\"msg_type\": \"stream\"},\n", " content: {text: message + newline,\n", " name: \"stdout\"}});\n", " }\n", " }\n", " window.jyp_println = jyp_print(cell, \"\\n\");\n", " window.jyp_print = jyp_print(cell, \"\");\n", "\n", " require([window.location.protocol + \"//calysto.github.io/javascripts/processing/processing.js\"], function() {\n", " Processing.logger.println = jyp_print(cell, \"\\n\");\n", " Processing.logger.print = jyp_print(cell, \"\");\n", " });\n", "\n", "\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " Sketch #9:
\n", "
\n", "
\n", "
\n", " \n", " \n", " \n", " \n", "
\n", "Sketch #9 state: Loading...
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "float g = 9.8; \n", "float dt; \n", "float t;\n", "\n", "class Ball {\n", " float x;\n", " float y;\n", " float vx;\n", " float vy;\n", " float w;\n", " float h;\n", " \n", " Ball() {\n", " x = width/2;\n", " y = 50;\n", " vx = 50.0;\n", " vy = 0.0;\n", " w = 10;\n", " h = 10;\n", " }\n", " \n", " void move() {\n", " vy = vy + g * dt;\n", "\n", " float dx = vx * dt; \n", " if (((x + dx) > width) || ((x + dx) < 0)) {\n", " vx = vx * -0.8;\n", " } else {\n", " x = x + dx;\n", " }\n", " float dy = vy * dt;\n", " if (((y + dy) > height) || ((y + dy) < 0)) {\n", " vy = vy * -0.8;\n", " } else {\n", " y = y + dy;\n", " }\n", " }\n", "\n", " void draw() {\n", " fill(255, 0, 0);\n", " ellipse(x, y, w, h);\n", " } \n", "}\n", "\n", "Ball pluto = new Ball();\n", "\n", "void setup() {\n", " size(200, 500);\n", " dt = 0.1; \n", " t = 0;\n", "}\n", "\n", "void draw() {\n", " background(200);\n", " t = t + dt;\n", " pluto.move();\n", " pluto.draw();\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What if we wanted to add more balls? We would need to add variables for vx, vy, x, y... for each ball!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.2 Bouncing Ball as an Object" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A better way is to let each ball keep track of its own properties. We do this by making a class definition, and storing each set of variables inside the Ball object.\n", "\n", "Here we will move all of the ball-specific variables \"into the Ball class\" and leave the others. \n", "\n", "Four steps for turning regular code into Object-Oriented code:\n", "\n", "1. Define a Ball \"object\" using the word `class`\n", "1. Move all global variables dealing with ball inside class\n", "1. Move all functions inside class. These are then called **methods**\n", " 1. There is a special method of the same name of the class called the `constructor`\n", " 1. Use the word `this` to represent the current object\n", "1. Create an **instance** of the object using the work `new`\n", "\n", "We define a class, create an **instance of a Ball**, and \"bounce\" it." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "// Globals:\n", "\n", "float g = 9.8; // gravity\n", "float dt = 0.1; // change in time\n", "float t = 0; // current time\n", "\n", "Ball ball; // the ball\n", "\n", "class Ball {\n", " float x;\n", " float y;\n", " int w;\n", " int h;\n", " float vx;\n", " float vy;\n", "\n", " // Jargon: the \"constructor\"\n", " Ball(float x, float y, int w, int h, float vx, float vy) {\n", " // Idea: \"this\" refers to the current ball\n", " this.x = x;\n", " this.y = y;\n", " this.w = w;\n", " this.h = h;\n", " this.vx = vx;\n", " this.vy = vy;\n", " }\n", " \n", " // Jargon: an object's function is called a \"method\"\n", " void moveYourself() {\n", " this.vy = this.vy + g * dt;\n", "\n", " float dx = this.vx * dt; \n", " if (((this.x + dx) > width) || ((this.x + dx) < 0)) {\n", " this.vx = this.vx * -0.8;\n", " } else {\n", " this.x = this.x + dx;\n", " }\n", "\n", " float dy = this.vy * dt;\n", " if (((this.y + dy) > height) || ((this.y + dy) < 0)) {\n", " this.vy = this.vy * -0.8;\n", " } else {\n", " this.y = this.y + dy;\n", " }\n", " }\n", " \n", " void drawYourself() {\n", " fill(255, 0, 0);\n", " ellipse(this.x, this.y, this.w, this.h);\n", " }\n", "}\n", "\n", "void setup() {\n", " size(200, 500);\n", " // Jargon: we create an \"instance\" of the Ball class:\n", " ball = new Ball(width/2, 50, 10, 10, 50.0, 0.0);\n", " t = 0;\n", "}\n", "\n", "void draw() {\n", " background(200);\n", " ball.moveYourself();\n", " ball.drawYourself();\n", " \n", " t = t + dt;\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we wanted to have two (or more) we need only create more **instances**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "// Globals:\n", "\n", "float g = 9.8; // gravity\n", "float dt = 0.1; // change in time\n", "float t = 0; // current time\n", "\n", "Ball ball0; // the balls\n", "Ball ball1; \n", "\n", "class Ball {\n", " float x;\n", " float y;\n", " int w;\n", " int h;\n", " float vx;\n", " float vy;\n", "\n", " // Jargon: the \"constructor\"\n", " Ball(float x, float y, int w, int h, float vx, float vy) {\n", " // Idea: \"this\" refers to the current ball\n", " this.x = x;\n", " this.y = y;\n", " this.w = w;\n", " this.h = h;\n", " this.vx = vx;\n", " this.vy = vy;\n", " }\n", " \n", " // Jargon: an object's function is called a \"method\"\n", " void moveYourself() {\n", " this.vy = this.vy + g * dt;\n", "\n", " float dx = this.vx * dt; \n", " if (((this.x + dx) > width) || ((this.x + dx) < 0)) {\n", " this.vx = this.vx * -0.8;\n", " } else {\n", " this.x = this.x + dx;\n", " }\n", "\n", " float dy = this.vy * dt;\n", " if (((this.y + dy) > height) || ((this.y + dy) < 0)) {\n", " this.vy = this.vy * -0.8;\n", " } else {\n", " this.y = this.y + dy;\n", " }\n", " }\n", " \n", " void drawYourself() {\n", " fill(255, 0, 0);\n", " ellipse(this.x, this.y, this.w, this.h);\n", " }\n", "}\n", "\n", "void setup() {\n", " size(200, 500);\n", " // Jargon: we create an \"instance\" of the Ball class:\n", " ball0 = new Ball(width/2, 50, 10, 10, 50.0, 20.0);\n", " ball1 = new Ball(width/4, 50, 10, 10, -29.0, -5.0);\n", " t = 0;\n", "}\n", "\n", "void draw() {\n", " background(200);\n", " ball0.moveYourself();\n", " ball0.drawYourself();\n", " \n", " ball1.moveYourself();\n", " ball1.drawYourself();\n", " \n", " t = t + dt;\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What if we wanted 10? Or 1,000?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.3 Introducing Arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To allow a large number of items, we use **arrays**.\n", "\n", "Using an array takes three steps:\n", "\n", "1. We use `Ball[] balls;` as the type to define the array\n", "2. We need to create space for each ball: `balls = new Ball[1];`\n", "3. We then create the instances of each ball in the array: `new Ball(...);`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "// Globals:\n", "\n", "float g = 9.8; // gravity\n", "float dt = 0.1; // change in time\n", "float t = 0; // current time\n", "\n", "Ball[] balls; // the balls\n", "\n", "class Ball {\n", " float x;\n", " float y;\n", " int w;\n", " int h;\n", " float vx;\n", " float vy;\n", "\n", " // Jargon: the \"constructor\"\n", " Ball(float x, float y, int w, int h, float vx, float vy) {\n", " // Idea: \"this\" refers to the current ball\n", " this.x = x;\n", " this.y = y;\n", " this.w = w;\n", " this.h = h;\n", " this.vx = vx;\n", " this.vy = vy;\n", " }\n", " \n", " // Jargon: an object's function is called a \"method\"\n", " void moveYourself() {\n", " this.vy = this.vy + g * dt;\n", "\n", " float dx = this.vx * dt; \n", " if (((this.x + dx) > width) || ((this.x + dx) < 0)) {\n", " this.vx = this.vx * -0.8;\n", " } else {\n", " this.x = this.x + dx;\n", " }\n", "\n", " float dy = this.vy * dt;\n", " if (((this.y + dy) > height) || ((this.y + dy) < 0)) {\n", " this.vy = this.vy * -0.8;\n", " } else {\n", " this.y = this.y + dy;\n", " }\n", " }\n", " \n", " void drawYourself() {\n", " fill(255, 0, 0);\n", " ellipse(this.x, this.y, this.w, this.h);\n", " }\n", "}\n", "\n", "void setup() {\n", " size(200, 500);\n", " balls = new Ball[1];\n", " // Jargon: we create an \"instance\" of the Ball class:\n", " balls[0] = new Ball(width/2, 50, 10, 10, 50.0, 0.0);\n", " t = 0;\n", "}\n", "\n", "void draw() {\n", " background(200);\n", " balls[0].moveYourself();\n", " balls[0].drawYourself();\n", " \n", " t = t + dt;\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is fairly easy to add more balls:\n", "\n", "1. Create more space in the array\n", "1. Create more instances\n", "1. Make sure we call move and update for each ball" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "// Globals:\n", "\n", "float g = 9.8; // gravity\n", "float dt = 0.1; // change in time\n", "float t = 0; // current time\n", "\n", "Ball [] balls; // the balls\n", "\n", "class Ball {\n", " float x;\n", " float y;\n", " int w;\n", " int h;\n", " float vx;\n", " float vy;\n", "\n", " // Jargon: the \"constructor\"\n", " Ball(float x, float y, int w, int h, float vx, float vy) {\n", " // Idea: \"this\" refers to the current ball\n", " this.x = x;\n", " this.y = y;\n", " this.w = w;\n", " this.h = h;\n", " this.vx = vx;\n", " this.vy = vy;\n", " }\n", " \n", " // Jargon: an object's function is called a \"method\"\n", " void moveYourself() {\n", " this.vy = this.vy + g * dt;\n", "\n", " float dx = this.vx * dt; \n", " if (((this.x + dx) > width) || ((this.x + dx) < 0)) {\n", " this.vx = this.vx * -0.8;\n", " } else {\n", " this.x = this.x + dx;\n", " }\n", "\n", " float dy = this.vy * dt;\n", " if (((this.y + dy) > height) || ((this.y + dy) < 0)) {\n", " this.vy = this.vy * -0.8;\n", " } else {\n", " this.y = this.y + dy;\n", " }\n", " }\n", " \n", " void drawYourself() {\n", " fill(255, 0, 0);\n", " ellipse(this.x, this.y, this.w, this.h);\n", " }\n", "}\n", "\n", "void setup() {\n", " size(200, 500);\n", " balls = new Ball[2];\n", " // Jargon: we create an \"instance\" of the Ball class:\n", " balls[0] = new Ball(width/2, 50, 10, 10, 50.0, 0.0);\n", " balls[1] = new Ball(width/4, 50, 10, 10, 50.0, 0.0);\n", " t = 0;\n", "}\n", "\n", "void draw() {\n", " background(200);\n", " balls[0].moveYourself();\n", " balls[0].drawYourself();\n", "\n", " balls[1].moveYourself();\n", " balls[1].drawYourself();\n", " \n", " t = t + dt;\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Properties of Arrays\n", "\n", "It can be even easier!\n", "\n", "Make code simpler:\n", "\n", "* Arrays have the property `.length`\n", "* Use for-loop to move and draw all of the balls" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "// Globals:\n", "\n", "float g = 9.8; // gravity\n", "float dt = 0.1; // change in time\n", "float t = 0; // current time\n", "\n", "Ball[] balls; // the balls\n", "\n", "class Ball {\n", " float x;\n", " float y;\n", " int w;\n", " int h;\n", " float vx;\n", " float vy;\n", " color c;\n", "\n", " // Jargon: the \"constructor\"\n", " Ball(float x, float y, int w, int h, float vx, float vy) {\n", " // Idea: \"this\" refers to the current ball\n", " this.x = x;\n", " this.y = y;\n", " this.w = w;\n", " this.h = h;\n", " this.vx = vx;\n", " this.vy = vy;\n", " this.c = color(random(255), random(255), random(255));\n", " }\n", " \n", " // Jargon: an object's function is called a \"method\"\n", " void moveYourself() {\n", " this.vy = this.vy + g * dt;\n", "\n", " float dx = this.vx * dt; \n", " if (((this.x + dx) > width) || ((this.x + dx) < 0)) {\n", " this.vx = this.vx * -0.8;\n", " } else {\n", " this.x = this.x + dx;\n", " }\n", "\n", " float dy = this.vy * dt;\n", " if (((this.y + dy) > height) || ((this.y + dy) < 0)) {\n", " this.vy = this.vy * -0.8;\n", " } else {\n", " this.y = this.y + dy;\n", " }\n", " }\n", " \n", " void drawYourself() {\n", " fill(this.c);\n", " ellipse(this.x, this.y, this.w, this.h);\n", " }\n", "}\n", "\n", "void setup() {\n", " size(200, 500);\n", " balls = new Ball[200];\n", " // Jargon: we create an \"instance\" of the Ball class:\n", " for (int i = 0; i < balls.length; i++) {\n", " balls[i] = new Ball(width * random(1), height * random(1), 10, 10, random(50) - 25, 0.0);\n", " }\n", " t = 0;\n", "}\n", "\n", "void draw() {\n", " background(128);\n", " for (int i = 0; i < balls.length; i++) {\n", " balls[i].moveYourself();\n", " balls[i].drawYourself();\n", " }\n", " t = t + dt;\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.4 Variations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cut and paste the above code and try some **variations**:\n", "\n", "1. More than one ball\n", "2. Add color to the balls\n", "3. Add a ball where you click the mouse" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.5 Collision Detection" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It would be cool if the balls could detect when they run into each other, just like it detects when it hits a wall. To do that, we go through the other balls, and identify when they \"overlap\".\n", "\n", "Then, we simply swap their velocities." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "// Globals:\n", "\n", "float g = 9.8; // gravity\n", "float dt = 0.1; // change in time\n", "float t = 0; // current time\n", "\n", "Ball [] balls; // the balls\n", "\n", "float distance(float x1, float y1, float x2, float y2) {\n", " return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));\n", "}\n", "\n", "class Ball {\n", " color c;\n", " float x;\n", " float y;\n", " int w;\n", " int h;\n", " float vx;\n", " float vy;\n", "\n", " Ball(color c, float x, float y, int w, int h, float vx, float vy) {\n", " this.c = c;\n", " this.x = x;\n", " this.y = y;\n", " this.w = w;\n", " this.h = h;\n", " this.vx = vx;\n", " this.vy = vy;\n", " }\n", " \n", " void move() {\n", " for (int i = 0; i < balls.length; i++) {\n", " if (balls[i] != this) {\n", " if (distance(this.x, this.y, balls[i].x, balls[i].y) < (this.w/2 + balls[i].w/2)) {\n", " float temp = this.vx;\n", " this.vx = balls[i].vx;\n", " balls[i].vx = temp;\n", " temp = this.vy;\n", " this.vy = balls[i].vy;\n", " balls[i].vy = temp;\n", " break;\n", " }\n", " }\n", " }\n", " this.vy = this.vy + g * dt; \n", " float dx = this.vx * dt; \n", " float dy = this.vy * dt;\n", " if (((this.x + dx) > width) || ((this.x + dx) < 0)) {\n", " this.vx = this.vx * -0.8;\n", " } else {\n", " this.x = this.x + dx;\n", " }\n", " if (((this.y + dy) > height) || ((this.y + dy) < 0)) {\n", " this.vy = this.vy * -0.8;\n", " } else {\n", " this.y = this.y + dy;\n", " }\n", " }\n", " \n", " void draw() {\n", " fill(this.c);\n", " ellipse(this.x, this.y, this.w, this.h);\n", " }\n", "}\n", "\n", "void setup() {\n", " size(200, 500);\n", " balls = new Ball[10];\n", " for (int i = 0; i < balls.length; i++) {\n", " balls[i] = new Ball(color(random(255), random(255), random(255)), random(width), random(40), 10, 10, random(50), 0.0);\n", " }\n", " t = 0;\n", "}\n", "\n", "void draw() {\n", " background(128);\n", " for (int i = 0; i < balls.length; i++) {\n", " balls[i].move();\n", " balls[i].draw();\n", " }\n", " t = t + dt;\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Variations**:\n", "\n", "1. Create different kinds of balls (e.g., different shapes... just use your previous drawObject here)\n", "1. Make the Physics more realistic (e.g., add some loss of energy, randomness)\n", "2. Create them where you click the mouse.\n", "2. Take into account the balls' masses (e.g., like [this](http://gamedevelopment.tutsplus.com/tutorials/when-worlds-collide-simulating-circle-circle-collisions--gamedev-769)\n", "3. Have some things in the environment that don't move (gravity should not effect them, and they have no velocities)\n", "4. Have some locations that inject velocities (e.g., shoot objects into the air)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "// Globals:\n", "\n", "float g = 9.8; // gravity\n", "float dt = 0.1; // change in time\n", "float t = 0; // current time\n", "\n", "Ball [] balls; // the balls\n", "\n", "float distance(float x1, float y1, float x2, float y2) {\n", " return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));\n", "}\n", "\n", "class Ball {\n", " color c;\n", " float x;\n", " float y;\n", " int w;\n", " int h;\n", " float vx;\n", " float vy;\n", "\n", " Ball(color c, float x, float y, int w, int h, float vx, float vy) {\n", " this.c = c;\n", " this.x = x;\n", " this.y = y;\n", " this.w = w;\n", " this.h = h;\n", " this.vx = vx;\n", " this.vy = vy;\n", " }\n", " \n", " void move() {\n", " for (int i = 0; i < COUNT; i++) {\n", " if (balls[i] != this) {\n", " if (distance(this.x, this.y, balls[i].x, balls[i].y) < (this.w/2 + balls[i].w/2)) {\n", " float temp = this.vx;\n", " this.vx = balls[i].vx;\n", " balls[i].vx = temp;\n", "\n", " temp = this.vy;\n", " this.vy = balls[i].vy;\n", " balls[i].vy = temp;\n", " break;\n", " }\n", " }\n", " }\n", " this.vy = this.vy + g * dt; \n", " float dx = this.vx * dt; \n", " float dy = this.vy * dt;\n", " if (((this.x + dx) > width) || ((this.x + dx) < 0)) {\n", " this.vx = this.vx * -0.8;\n", " } else {\n", " this.x = this.x + dx;\n", " }\n", " if (((this.y + dy) > height) || ((this.y + dy) < 0)) {\n", " this.vy = this.vy * -0.8;\n", " } else {\n", " this.y = this.y + dy;\n", " }\n", " }\n", " \n", " void draw() {\n", " fill(this.c);\n", " ellipse(this.x, this.y, this.w, this.h);\n", " }\n", "}\n", "\n", "void setup() {\n", " size(200, 500);\n", " balls = new Ball[100];\n", " COUNT = 0;\n", " t = 0;\n", "}\n", "\n", "int COUNT = 0;\n", "\n", "void mousePressed() {\n", " balls[COUNT] = new Ball(color(random(255), random(255), random(255)), \n", " mouseX, mouseY, 10, 10, random(50) - 25, 0);\n", " COUNT++;\n", "}\n", "\n", "void draw() {\n", " background(128);\n", " for (int i = 0; i < COUNT; i++) {\n", " balls[i].move();\n", " balls[i].draw();\n", " } \n", " t = t + dt;\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Calysto Processing", "language": "java", "name": "calysto_processing" }, "language_info": { "codemirror_mode": { "name": "text/x-java", "version": 2 }, "file_extension": ".java", "mimetype": "text/x-java", "name": "java" } }, "nbformat": 4, "nbformat_minor": 0 }